package edu.uc.labs.MobilePrinting.PrintUtils;

import edu.uc.labs.MobilePrinting.Fetch.PPDFetcher;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.apache.log4j.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import edu.uc.labs.MobilePrinting.Configurator;
import java.io.File;


/**
 *
 * @author Matt Silbernagel
 */
public class PrinterInstaller {

    private String osName, cache_dir, winScriptsPath, delim, filename;
    final static String PORTNAME = Configurator.PORTNAME, PRINTERNAME = Configurator.PORTNAME;
    private Printer printer = null;
    private Configurator conf = new Configurator();
    private Logger logger = conf.getLogger();

    public PrinterInstaller( Printer prn ){
        printer = prn;
        osName = Configurator.OS;
        cache_dir = Configurator.CACHEDIR;
        delim = Configurator.DELIM;
        winScriptsPath = Configurator.WINSCRIPTSPATH; 
        filename = cache_dir + "ppd" + delim + printer.getZone() + delim + printer.getQueue() + ".ppd";
        
    }

    public void install() {
        if (osName.matches("Windows(.)*")){
            try {
                logger.debug("You appear to using a windows machine");
                boolean uPort = winAddPort();
                if(uPort){
                    // Successfully updated/add the port
                    // not checking for the printer
                    if(!winCheckForPrinter()){
                    	 winAddPrinter();
                    }
                }
            } catch (IOException ex) {
                logger.error(ex.toString());
            }

        } else if(osName.matches("Linux") || osName.matches("SunOS")){
           logger.debug("This is Linux");

           boolean check = checkForPPD("linux");
           if(check){
               // The ppd is in place...
               logger.debug("The printer is being installed...");
                try {
                    installNixPrinter();
                    /*try {
                        PrinterCache.writeCache(printer);
                    } catch (ParserConfigurationException ex) {
                        logger.error(ex);
                    }
                     *
                     */
                } catch (IOException ex) {
                    logger.error(ex.toString());
                }
           } else {
               logger.debug("Could not find the PPD file...");
           }

        } else if(osName.startsWith("Mac OS X")){
            logger.debug("This is Mac OS X");
            boolean check = checkForPPD("mac");
            if(check) {
                logger.debug("The printer is being installed...");
                try {
                    installNixPrinter();
                    /*
                    try{
                        PrinterCache.writeCache(printer);
                    } catch (ParserConfigurationException ex) {
                        logger.error(ex);
                    }
                     *
                     */
                } catch (IOException ex){
                    logger.debug("The printer couldn't be installed");
                    logger.error(ex.getMessage());
                }
            } else {
                logger.debug("Could not find the PPD file...");
            }
        }
        
    }
    
    public boolean winAddPort() throws IOException {
        String line = null;
        String addPortcmd = "cscript.exe " + winScriptsPath + "\\prnport.vbs -a -r "
                + PORTNAME + " -h " + printer.getServer() + " -q " + printer.getQueue() + " -o lpr";

        System.out.println("Updating port... ");
        Process p = Runtime.getRuntime().exec(addPortcmd);
        boolean successful = false;
        // What does the output of the command report
        BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
        while ((line = input.readLine()) != null) {
            System.out.println(line);
            Pattern pattern = Pattern.compile("Created/updated port (.)*");
            Matcher mat = pattern.matcher(line);
            if (mat.find()) {
                successful = true;
            }
        }
        return successful;
    }

    private void winAddPrinter() throws IOException{
        String unc = "\\\\" + Configurator.HTTP_SERVER + Configurator.DELIM + "Printers" + Configurator.DELIM + "HPUniversal" + Configurator.DELIM + "hpcu094d.inf";
        String s = null;
        String [] insPrinter = { "rundll32", "printui.dll,PrintUIEntry", "/if", "/b", 
        					     PRINTERNAME, "/f", unc, "/u", "/r", PORTNAME, "/m", "HP Universal Printing PS" };        
                       
        Process p = Runtime.getRuntime().exec(insPrinter);
        BufferedReader stdInput = new BufferedReader(new
                 InputStreamReader(p.getInputStream()));

        BufferedReader stdError = new BufferedReader(new
                 InputStreamReader(p.getErrorStream()));

        // read the output from the command
        logger.debug("Here is the standard output of the command:\n");

        while ((s = stdInput.readLine()) != null) {
            logger.debug(s);
        }

       // read any errors from the attempted command
       logger.debug("Here is the standard error of the command (if any):\n");
       while ((s = stdError.readLine()) != null) {
            logger.debug(s);
       }

    }

    private void winPausePrinter(){
    	
    	
    }
    
    private boolean winCheckForPrinter() throws IOException {
        boolean isInstalled = false;
        String line = null;
        String checkPrinter = "cscript.exe " + winScriptsPath + "\\prnmngr.vbs -l";

        System.out.println("Checking for existence of " + PRINTERNAME + "...");
        Process p = Runtime.getRuntime().exec(checkPrinter);

        BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
        while ((line = input.readLine()) != null) {
            Pattern pattern = Pattern.compile("Printer name " + PRINTERNAME + "(.)*");
            Matcher mat = pattern.matcher(line);
            if (mat.find()) {
                System.out.println("There is printer installed called " + PRINTERNAME);
                isInstalled = true;
            }
        }
        return isInstalled;
    }

    private boolean checkForPPD(String os){
        boolean doesExist = false;
        File f = new File(filename);
        for(int i=0; i<4; i++){
            if(f.exists()){
                // The ppd already exists, start the installation
                logger.debug("The ppd already exists...");
                doesExist = true;
                break;
            } else {
                logger.debug("The ppd does not exist yet...");
                PPDFetcher fetch = new PPDFetcher(Configurator.HTTP_SERVER, printer.getZone(), printer.getQueue(), os);
                fetch.writeToFile();
            }
        }
        return doesExist;
    }

    private boolean installNixPrinter() throws IOException{
        String s = null;

        String[] insPrinter = {"/usr/sbin/lpadmin",  "-p", Configurator.PRINTERNAME, "-o",
                               "printer-is-shared=false",  "-v",  "lpd://" +
                                printer.getServer() + "/" + printer.getQueue(),  "-L", printer.getLocation(),
                                "-D", Configurator.PRINTERNAME, "-P", filename, "-E"};
        logger.debug(insPrinter);
        Process p = Runtime.getRuntime().exec(insPrinter);

        BufferedReader stdInput = new BufferedReader(new
                 InputStreamReader(p.getInputStream()));

        BufferedReader stdError = new BufferedReader(new
                 InputStreamReader(p.getErrorStream()));

        // read the output from the command
        System.out.println("Here is the standard output of the command:\n");
        
        while ((s = stdInput.readLine()) != null) {
            System.out.println(s);
        }

       // read any errors from the attempted command
       System.out.println("Here is the standard error of the command (if any):\n");
       while ((s = stdError.readLine()) != null) {
            System.out.println(s);
       }


        return true;

    }


    

}
